//Constants
        //log levels
        var logLevels = {
            DEBUG:  "DEBUG",
            INFO:   "INFO",
            WARN:   "WARN",
            ERROR:  "ERROR"
        };
        //all actions that are provided by this program
        var possibleActions = {
            REGISTER:            "register",
            LOGIN:               "login",
            LOGOUT:              "logout",
            LIST:                "list",
            INVITE_USER:         "inviteUser",
            RESPONSE_IVITATION:  "responseInvitation",
            START_CHAT:          "startChat",
            CANCEL_CHAT:         "cancelChat",
            SEND_CHAT_MESSAGE:   "sendChatMessage",
            CHECK_FOR_MESSAGES:  "checkForMessage"
        };
      
        //all message types, returned from Web Service
        var messageTypes = {
            MSG_NO_MESSAGES:     "MSG_NO_MESSAGES",
            MSG_USER_ONLINE:     "MSG_USER_ONLINE",
            MSG_USER_OFFLINE:    "MSG_USER_OFFLINE",
            MSG_CHALLENGE:       "MSG_CHALLENGE",
            MSG_RESPONSE:        "MSG_RESPONSE",
            MSG_START_CHAT:      "MSG_START_CHAT",
            MSG_CANCEL_CHAT:     "MSG_CANCEL_CHAT",
            MSG_CHAT_MESSAGE:    "MSG_CHAT_MESSAGE"
        };
        
        //Parameters taken from the phone
        var userMSISDN;
        var userPassword;//Keep user password, for current program
        var phonebook = ["+359883382012","+359883382022","+359883382021"]; //must be replaced with Phone Contacts. But leave this for browser support.
        var database; //database object used to save and retrieve information from
        
        //parameters that should be configurable
        var messageCheckInterval = 1000; //in miliseconds
        var serviceURL = "http://mobilecryptochat.apphb.com/MobileCryptoChatService.svc";
        var globalLogLevel = logLevels.DEBUG;
      
        //parameters for this user session
        var messageLoopID; //used to stop/start automatic message reading
        var sessionID;
        var mapUserKey = {};//contain keys for chat with specific user
        var mapUserChallange = {}; //keep chalenges received send to particular user. This way we can check returned response from challange.
      
        //keep how many times Ajax request to server fail with General failuire. If it fails more than 10 times, logout user.
        var numberOfGeneralFailures = 0;
        
     	// Wait for PhoneGap to load
        //
        document.addEventListener("deviceready", onDeviceReady, false);

        // PhoneGap is ready
        //
        function onDeviceReady() {
            // find all contacts phone numbers
            navigator.contacts.find(
            		["phoneNumbers"],
					function(contacts) {
            			//on success
            			phonebook = [];
            			var position = 0;
                        for (var i=0; i<contacts.length; i++) {
                        	//handle contacts with multiple munbers
                        	for (var j=0; j<contacts[i].phoneNumbers.length; j++) {
                        		phonebook[position] = contacts[i].phoneNumbers[j].value;
                        		position++;
                            }
                        }
         			},
         			function(contactError) {
         				//on error
         	            showNoConfirmPopup('Error during contact loading!');
         	            logProgramMessage("Error occured during contact loading! "+contactError, logLevels.ERROR);
         	        });
            
        }

        $(function() {
            $(document).ready(function(){
                //load settings of user
                $('#messageCheckInterval').val(messageCheckInterval);
                $('#logLevel').val(globalLogLevel);
                $('#serviceURL').val(serviceURL);
                
                //correct focus
                focusFirstVisibleTextField();
            });
          
            //implement pressing enter catch
            $('input').live('keypress',function(e){
                code= (e.keyCode ? e.keyCode : e.which);
                if (code == 13 || code == 10){
                    //trigger click of closest button - do not automaticaly trigger close buttons
                    $(this).parent().find('a[data-role="button"]').not('.closeChatSession').trigger('click');
                }
            });
            
            //register pageshow event to correct the focus
            $('#loginPage').live('pageshow', function () {
            	focusFirstVisibleTextField();  
            });
            $('#usersPage').live('pageshow', function () { 
            	focusFirstVisibleTextField();  
            });
            $('#startChatPage').live('pageshow', function () {
            	focusFirstVisiblePasswordField();  
            });
            $('#chatInvitationPage').live('pageshow', function () {
            	focusFirstVisiblePasswordField();  
            });

            $("#loginButton").click(function(){
                var userPass = $("#userPassword").val();
                var userMSISDNentered = $('#userMSISDN').val();
                //validate phone
                if(invalidUserMSISDN(userMSISDNentered)){
                    showNoConfirmPopup("Invalid phone number");
                    return;
                }
                
                //validate password
                if(userPass == ''){
                    showNoConfirmPopup("Please enter password!");
                    return false;
                }
              
                //save data
                userMSISDN = userMSISDNentered;
                userPassword = userPass;
                
                //try to login user
                var authCode = SHA1(userMSISDN+userPassword);
                var data = {
                    "msisdn":userMSISDN,
                    "authCode":authCode
                };
                sendAjaxRequest(serviceURL+"/login", "POST", data, possibleActions.LOGIN);
            });
          
            $("#registerButton").click(function(){
                var userPass = $("#regPassword").val();
                var confirmPass = $("#regPasswordConfirm").val();
                var userMSISDNentered = $('#registerUserMSISDN').val();
                //validate phone
                if(invalidUserMSISDN(userMSISDNentered)){
                    showNoConfirmPopup("Invalid phone number");
                    return;
                }
                
                //validate password
                if(userPass == ''){
                    showNoConfirmPopup("Please enter password!");
                    return false;
                } else if(confirmPass != userPass){
                	showNoConfirmPopup("Confirm value didn't match entered password!");
                    return false;
                }
                
                //keep entered data
                userMSISDN = userMSISDNentered;
                userPassword = userPass;
              
                //try to register user
                var authCode = SHA1(userMSISDN+userPassword);
                var data = {
                    "msisdn":userMSISDN,
                    "authCode":authCode
                };
                sendAjaxRequest(serviceURL+"/register", "POST", data, possibleActions.REGISTER);
            });
          
            $("#exitButton").click(function(){
                //stop message reading
                stopMessageReading();
                //try to logout user
                sendAjaxRequest(serviceURL+"/logout/"+sessionID, "GET", {}, possibleActions.LOGOUT);
            });
          
            $('#homeButton').click(function(){
                var buttonTheme = $(this).attr("data-theme");
                var buttonId = $(this).attr("id");
                if( buttonTheme == "c"){
                    //it is already selected. no action
                    return;
                }
              
                //show UsersDiv
                showTabInPage("usersPage", "onlineUsers");
              
                //mark button as selected
                markButtonAsSelected(buttonId);
            });
          
            $('.startChat').live("click",function(){
                var corespondentMSISDN = $(this).html();
                //check whether we already have chat session with this user
                if($('#button'+corespondentMSISDN.substring(1)).length !== 0){
                    //we already have chat with this user
                    //show chat div
                    showTabInPage("usersPage", "div"+corespondentMSISDN.substring(1));
                   
                    //select button
                    markButtonAsSelected("button"+corespondentMSISDN.substring(1));
                    return;
                }
                
                //check wheter user has invited us for chat
                if($('#buttonChallange'+corespondentMSISDN.substring(1)).length !== 0){
                    //this user has invited us - click invite pending button
                    //show chat div
                    $('#buttonChallange'+corespondentMSISDN.substring(1)).click();
                    return;
                }
                
                //check whether we already send invitation to this user
                if(mapUserChallange[corespondentMSISDN] > -1) {
                	showNoConfirmPopup("Wait till user respond to your invitation!");
                	logProgramMessage("You already invite user: "+corespondentMSISDN
                			+" with challange number: "+mapUserChallange[corespondentMSISDN], logLevels.INFO);
                	return;
                }
                
                //edit start chat page
                $('#startChatPage div[data-role="footer"] h1').html(corespondentMSISDN);
                $.mobile.changePage( "index.html#startChatPage", {
                    transition: "fade",
                    reverse: false,
                    changeHash: false
                });
            });
          
            $('#canselStartChat').click(function(){
                $.mobile.changePage( "index.html#usersPage", {
                    transition: "fade",
                    reverse: false,
                    changeHash: false
                });
                //clear data
                clearInputData("startChatRequestForm");
            });
            
            $('#canselChatInvitation').click(function(){
                corespondentMSISDN = $('#chatInvitationPage div[data-role="footer"] h1').html();
                //clear data
                clearInputData("chatInvitationReseivedForm");
                
                //send chat-close event
                logProgramMessage("You have close chat invitation -> send 'cancel-chat' event!", logLevels.DEBUG);
                var data = {
                    "sessionID":sessionID,
                    "recipientMSISDN":corespondentMSISDN
                };
                sendAjaxRequest(serviceURL+"/cancel-chat", "POST", data, possibleActions.CANCEL_CHAT);
                
                //redirect to users page
                $.mobile.changePage( "index.html#usersPage", {
                    transition: "fade",
                    reverse: false,
                    changeHash: false
                });
            });
          
            $('#sendChallange').click(function(){
                var key = $('#chatKeyChalange').val();
                var corespondentMSISDN = $('#startChatPage div[data-role="footer"] h1').html();
              
                //save key for this user
                mapUserKey[corespondentMSISDN] = key;
                //generate random number
                var numRand = Math.floor(Math.random()*1000000000);
                mapUserChallange[corespondentMSISDN] = numRand;
              
                logProgramMessage("Send challange number: " + numRand + " to user: "+corespondentMSISDN, logLevels.DEBUG);
                //construct body of message
                var challange = GibberishAES.enc(numRand, key);
                var data = {
                    "sessionID":sessionID,
                    "recipientMSISDN":corespondentMSISDN,
                    "challenge":challange
                };
              
                sendAjaxRequest(serviceURL+"/invite-user", "POST", data, possibleActions.INVITE_USER);
              
                //show info
                showNoConfirmPopup("You will be notified when user accept the chat!");
                $.mobile.changePage( "index.html#usersPage", {
                    transition: "fade",
                    reverse: false,
                    changeHash: false
                });

                //clear data
                clearInputData("startChatRequestForm");
            });
          
            $('#sendResponse').click(function(){
                var key = $('#chatKeyResponse').val();
                var corespondentMSISDN = $('#chatInvitationPage div[data-role="footer"] h1').html();
              
                //save key for this user
                mapUserKey[corespondentMSISDN] = key;
                //generate random number
                var challangeNumber = $("#challangeKeyReseived").val();

                //construct body of message
                var challangeReseived;
                try{
                    challangeReseived = GibberishAES.dec(challangeNumber, key);
                } catch(e){
                    //Key maybe is wronk. We will just send -1 to cancel chat session
                    challangeReseived = -1;
                }
              
                logProgramMessage("Reseived Challange number: " + challangeReseived + " from user: " + corespondentMSISDN, logLevels.DEBUG);
                var response = GibberishAES.enc(999999999 - challangeReseived, key);
                var data = {
                    "sessionID":sessionID,
                    "recipientMSISDN":corespondentMSISDN,
                    "response":response
                };
              
                sendAjaxRequest(serviceURL+"/response-chat-invitation", "POST", data, possibleActions.RESPONSE_IVITATION);
              
                //show info
                showNoConfirmPopup("You will be notified when user starts the chat!");
                $.mobile.changePage( "index.html#usersPage", {
                    transition: "fade",
                    reverse: false,
                    changeHash: false
                });

                //clear data
                clearInputData("chatInvitationReseivedForm");
            });
          
            $('.sendMessage').live("click",function(){
                //strip send keyword from ID and add + sign, as it is not valid for HTML identifier
                var corespondentMSISDN = "+" + $(this).attr('id').substring(4);
               
                var message = $('#message'+corespondentMSISDN.substring(1)).val();
                if(message == ""){
                    //just return
                    return;
                } else if(message.length > 31){
                    //this is maximum allowed characters by the encoding.
                    //this check is in case somthing happen with input maxlength attribute
                    showNoConfirmPopup("Maximun message length is 31 symbols.");
                    return;
                }
               
                //send message
                var encryptedMsg = GibberishAES.enc(message, mapUserKey[corespondentMSISDN]);
                var data = {
                    "sessionID":sessionID,
                    "recipientMSISDN":corespondentMSISDN,
                    "encryptedMsg":encryptedMsg
                };
                logProgramMessage("Send chat message: "+message+" to user: "+corespondentMSISDN, logLevels.DEBUG);
                sendAjaxRequest(serviceURL+"/send-chat-message", "POST", data, possibleActions.SEND_CHAT_MESSAGE, {"chatMessage":message, "corespondentMSISDN":corespondentMSISDN});
            });
            
            $('.closeChatSession').live("click",function(){
                //strip send keyword from ID and add + sign, as it is not valid for HTML identifier
                var corespondentMSISDN = "+" + $(this).attr('id').substring(5);
               
                //clear data
                clearChatInfoWithUser(corespondentMSISDN);
                
                //send chat-close event
                logProgramMessage("Close chat session with user: "+corespondentMSISDN+" and send 'cancel-chat' event.'", logLevels.DEBUG);
                var data = {
                    "sessionID":sessionID,
                    "recipientMSISDN":corespondentMSISDN,
                };
                sendAjaxRequest(serviceURL+"/cancel-chat", "POST", data, possibleActions.CANCEL_CHAT);
                
                //redirect to users page
                $.mobile.changePage( "index.html#usersPage", {
                    transition: "fade",
                    reverse: false,
                    changeHash: false
                });
            });
          
            $('#displayLogin').click(function(){
                //Show login form and hide register
                $('#loginForm').show();
                $('#registerForm').hide().trigger( 'updatelayout' );
                //change arows
                $(this).parents('li').attr("data-icon","arrow-d");
                $(this).parents('li').find('.ui-icon-arrow-r').removeClass('ui-icon-arrow-r').addClass('ui-icon-arrow-d');
                $('#displayRegister').parents('li').attr("data-icon","arrow-r");
                $('#displayRegister').parents('li').find('.ui-icon-arrow-d').removeClass('ui-icon-arrow-d').addClass('ui-icon-arrow-r');
                
                //correct focus
                focusFirstVisibleTextField();
            });
          
            $('#displayRegister').click(function(){
                //Show register form and hide login
                $('#registerForm').show();
                $('#loginForm').hide().trigger( 'updatelayout' );
                //change arows
                $(this).parents('li').attr("data-icon","arrow-d");
                $(this).parents('li').find('.ui-icon-arrow-r').removeClass('ui-icon-arrow-r').addClass('ui-icon-arrow-d');
                $('#displayLogin').parents('li').attr("data-icon","arrow-r");
                $('#displayLogin').parents('li').find('.ui-icon-arrow-d').removeClass('ui-icon-arrow-d').addClass('ui-icon-arrow-r');

                //correct focus
                focusFirstVisibleTextField();
            });
          
            $('.activeChatSessionButton').live("click",function(){
                //check whether button is selected
                 var buttonTheme = $(this).attr("data-theme");
                 var buttonId = $(this).attr("id");
                 if( buttonTheme == "c"){
                   //it is already selected. no action
                   return;
                 }
                 
                //show appropriate div
                showTabInPage("usersPage", "div"+buttonId.substring(6));
                
                //select button
                markButtonAsSelected(buttonId);
            });
          
            $('.challangeReceivedButton').live("click",function(){
                var buttonId = $(this).attr("id");
                var corespondentMSISDN = "+"+buttonId.substring(15);
                var challangeKeyReseived = $('#challangeKeyReseived'+corespondentMSISDN.substring(1)).val();
                logProgramMessage("Challange key: "+challangeKeyReseived+" received from user: "+corespondentMSISDN, logLevels.DEBUG);
            
                //show button wich will point to invitation
                //edit start chat page
                $('#chatInvitationPage div[data-role="footer"] h1').html(corespondentMSISDN);
                $('#challangeKeyReseived').val(challangeKeyReseived);
                $.mobile.changePage( "index.html#chatInvitationPage", {
                    transition: "fade",
                    reverse: false,
                    changeHash: false
                });
                //remove button as it is not needed anymore
                $(this).remove().trigger( 'updatelayout' );
               });
            
            $('#settingsButton').click(function(){
                var buttonTheme = $(this).attr("data-theme");
                var buttonId = $(this).attr("id");
                if( buttonTheme == "c"){
                    //it is already selected. no action
                    return;
                }
              
                //show UsersDiv
                showTabInPage("loginPage", "settingsPage");
              
                //selected button
                markButtonAsSelected(buttonId);
            });
            
            $('#saveSettings').click(function(){
                //validate entered values
                var messageCheckIntervalChanged = $('#messageCheckInterval').val();
                if(isNaN(messageCheckIntervalChanged) || messageCheckIntervalChanged < 500){
                    showNoConfirmPopup("Please enter valid check interval (>500ms)!");
                    return;
                }
                
                
                //save settings
                globalLogLevel = $('#logLevel').val();
                serviceURL = $('#serviceURL').val();
                messageCheckInterval = messageCheckIntervalChanged;
              
                //show Login Form 
                showTabInPage("loginPage", "loginPageForms");
              
                //deselect the button
                deselectAllButtons();
                
                //show message for successfull saving
                logProgramMessage("Settings successfully saved. Log level: "+globalLogLevel
                		+" Check interval: "+messageCheckInterval
                		+" Service URL:"+serviceURL, logLevel);
                showNoConfirmPopup("Settings saved successfully!");
            });
            
            $('#cancelSettingsSaving').click(function(){
                //reset changes
                 $('#logLevel').val(globalLogLevel);
                 $('#serviceURL').val(serviceURL);
                 $('#messageCheckInterval').val(messageCheckInterval);
                 
                //redirect to login forms
                showTabInPage("loginPage", "loginPageForms");
              
                //deselect the button
                deselectAllButtons();
            });
            
            //show Logs page
            $('#programLogsButton').click(function(){
                //show appropriate tab
                showTabInPage("usersPage", "programLogsPage");
              
                //deselect the button
                markButtonAsSelected('programLogsButton');
            });
            
            $('#showOfflineUsers').live('click',function(){
            	$('.offlineUsers').show();
            	//change ID of button to know when to hide items
            	$(this).attr('id','hideOfflineUsers');
            	//change arows
                $(this).parents('li').attr("data-icon","arrow-d");
                $(this).parents('li').find('.ui-icon-arrow-r').removeClass('ui-icon-arrow-r').addClass('ui-icon-arrow-d');
                //refresh list
                $("#onlineUsersListview").listview('refresh').trigger('updatelayout');
            });
            
            $('#hideOfflineUsers').live('click',function(){
            	$('.offlineUsers').hide();
            	//change ID of button to know when to show items
            	$(this).attr('id','showOfflineUsers');
            	//change arows
                $(this).parents('li').attr("data-icon","arrow-r");
                $(this).parents('li').find('.ui-icon-arrow-d').removeClass('ui-icon-arrow-d').addClass('ui-icon-arrow-r');
                //refresh list
                $("#onlineUsersListview").listview('refresh').trigger('updatelayout');
            });
        });
      
        function processAjaxResponseSuccess(response, action, callbackInfo){
            var result = jQuery.parseJSON(response);
            if(action == possibleActions.LOGIN){
                sessionID = result.sessionID;
                logProgramMessage("Successfully Login! SessionID: "+sessionID, logLevels.INFO);
              
                $.mobile.changePage( "index.html#usersPage", {
                    transition: "fade",
                    reverse: false,
                    changeHash: false
                });
                //clear form data
                clearInputData("loginPageForms");
              
                //list users
                listUsersFromServer();
              
                //start message reading
                startMessageReading();
            } else if (action == possibleActions.REGISTER){
                sessionID = result.sessionID;
                logProgramMessage("Registration was successfull! SessionID: "+sessionID, logLevels.INFO);
              
                $.mobile.changePage( "index.html#usersPage", {
                    transition: "fade",
                    reverse: false,
                    changeHash: false
                });
                //clear form data
                clearInputData("loginPageForms");
              
                //list users
                listUsersFromServer();
              
                //start message reading
                startMessageReading();
            } else if(action == possibleActions.LOGOUT){
            	showNoConfirmPopup("Logout successfully!");
            	//clear user data
            	logoutUserLocally();
            } else if(action == possibleActions.LIST){
                logProgramMessage("List command executed successfully.", logLevels.DEBUG);
                //create array with numbers
                if(response.length > 4){
                    //remove [" and "] symbols
                    response = response.substring(2,response.length-2);
                    populateListedUsers(response.split('","'));
                } else {
                    //no users!!!
                }
                //show appropriate div
                showTabInPage("usersPage", "onlineUsers");
                //select home button to selected
                markButtonAsSelected("homeButton");
            } else if(action == possibleActions.INVITE_USER){
                logProgramMessage("Invitation for chat to user send successfully! Reponse: "+ result.status, logLevels.DEBUG);
            } else if(action == possibleActions.RESPONSE_IVITATION){
                logProgramMessage("Response for received invitation send successfully! Reponse: "+ result.status, logLevels.DEBUG);
            } else if(action == possibleActions.START_CHAT){
                logProgramMessage("Start chat command executed successfull! Reponse: "+ result.status, logLevels.DEBUG);
                var corespondentMSISDN = callbackInfo.corespondentMSISDN;
                startChatWithUser(corespondentMSISDN);
            } else if(action == possibleActions.CANCEL_CHAT){
                logProgramMessage("Cancel chat command executed successfully. Reponse: "+ result.status, logLevels.DEBUG);
            } else if(action == possibleActions.SEND_CHAT_MESSAGE){
                logProgramMessage("Chat message send successfully. Reponse: "+ result.status, logLevels.DEBUG);
                //evaluate message
                var corespondentMSISDN = callbackInfo.corespondentMSISDN;
                var message = callbackInfo.chatMessage;
                logChatMessage(corespondentMSISDN, message, false);
            } else if(action == possibleActions.CHECK_FOR_MESSAGES){
                //evaluate message
                executeReseivedMessage(response);
            }
        }
      
        function processAjaxResponseFailure(jqXHR, textStatus, thrownError, action, callbackInfo){
            var responseData = jQuery.parseJSON(jqXHR.responseText);
            if(action == possibleActions.LOGIN){
                if(jqXHR.status==403){
                	showNoConfirmPopup('Invalid username or password. Please try again!');
                }else if(jqXHR.status==404){
                    showNoConfirmPopup('Error during sending data!\n' + responseData.errorMsg);
                    logProgramMessage('Error during sending data! ' + responseData.errorMsg, logLevels.ERROR);
                }else {
                	showNoConfirmPopup('Unknow Error.\nCheck Log for more details.');
                    logProgramMessage('Unknow Error. Status code: ' + jqXHR.status + ' Response:'+jqXHR.responseText + " Error:" + thrownError, logLevels.ERROR);
                }

            } else if(action == possibleActions.REGISTER){
                if(jqXHR.status == 404){
                    showNoConfirmPopup('Error during sending data!\n' + responseData.errorMsg);
                    logProgramMessage('Error during sending data! ' + responseData.errorMsg, logLevels.ERROR);
                }else {
                	showNoConfirmPopup('Unknow Error.\nCheck Log for more details.');
                    logProgramMessage('Unknow Error. Status code: ' + jqXHR.status + ' Response:'+jqXHR.responseText + " Error:" + thrownError, logLevels.ERROR);
                }
                
            } else {
               	if(action == possibleActions.LOGOUT){
                	if(jqXHR.status == 403){
                		//no need to show this message, as user want to logout.
                    }else {
                    	showNoConfirmPopup('Unknow Error.\nCheck Log for more details.');
                        logProgramMessage('Unknow Error. Status code: ' + jqXHR.status + ' Response:'+jqXHR.responseText + " Error:" + thrownError, logLevels.ERROR);
                    }
                	//clean user data
                	logoutUserLocally();
                } else {
                	//for all other actions -> handling will be the same
                    if(jqXHR.status == 403){
                    	showNoConfirmPopup('Invalid session ID!You will be logged out.');
                        logProgramMessage('Invalid session ID! ' + responseData.errorMsg, logLevels.ERROR);
                        //no good -> we have nothing to do with wrong Session ID -> logout user
                        //clean user data
                    	logoutUserLocally();
                    }else if(jqXHR.status == 404){
                        showNoConfirmPopup('Error during sending data!\n' + responseData.errorMsg);
                        logProgramMessage('Error during sending data! ' + responseData.errorMsg, logLevels.ERROR);
                    }else {
                    	showNoConfirmPopup('Unknow Error.\nCheck Log for more details.');
                        logProgramMessage('Unknow Error. Status code: ' + jqXHR.status + ' Response:'+jqXHR.responseText + " Error:" + thrownError, logLevels.ERROR);
                    }
                    
                }
        	}
        }
        
        function sendAjaxRequest(url, type, data, action, callbackInfo){
            $.ajax({
                url: url,
                type: type,
                processData: false, 
                contentType: "application/json",
                timeout: 10000,
                data: JSON.stringify(data),
                dataType: "text"
            }).done(function( response ) {
            	//reset failure counter
            	numberOfGeneralFailures = 0;
                processAjaxResponseSuccess(response, action, callbackInfo);
            }).fail(function(jqXHR, textStatus, thrownError) {
            	//if this is Login or Register command -> we should not count failures
            	var countFailures = true;
            	if(action == possibleActions.LOGIN || action == possibleActions.REGISTER){
            		countFailures = false;
            	}
            	
            	//handle some common errors here
                if(jqXHR.status == 0){
                	//here we may be offline or problem with simultantious ajax request happend.
                  	logProgramMessage('You are offline!! Please Check Your Network. Error code: 0. ' + thrownError, logLevels.ERROR);
                	if(countFailures){
                    	numberOfGeneralFailures++;
                	} else {
                		showNoConfirmPopup("You are offline!!\n Please Check Your Network.");
                	}
                }else if(jqXHR.status == 500){
                	//internal server error -> general failure
                    logProgramMessage('Internel Server Error. Error code: 500. ' + thrownError, logLevels.ERROR);
                	if(countFailures){
                    	numberOfGeneralFailures++;
                	} else {
                		showNoConfirmPopup('Internel Server Error. Error code: 500. ');
                	}
                }else if(textStatus == 'parsererror'){
                	//this is not general failure -> we actually receive response, but wrong one :)
                    logProgramMessage('Error.Parsing Request failed. Error code: '+ jqXHR.status + ". " + thrownError, logLevels.ERROR);
                	if(!countFailures){
                		showNoConfirmPopup('Error.Parsing Request failed. Error code: '+ jqXHR.status + ". ");
                	}
                }else if(textStatus == 'timeout'){
                	//request has time out -> again general failure
                    logProgramMessage('Request Time out.Error code: '+ jqXHR.status + ". " + thrownError,logLevels.ERROR);
                	if(countFailures){
                        numberOfGeneralFailures++;
                	} else {
                		showNoConfirmPopup('Request Time out.Error code: '+ jqXHR.status + ". ");
                	}
                }else {
                    processAjaxResponseFailure(jqXHR, textStatus, thrownError, action, callbackInfo);
                }
            	
            	//check whether we have to logout user
            	if(numberOfGeneralFailures >= 10){
            		showNoConfirmPopup("Too many general failures. You will be logouted!!!");
            		//clear user data
            		logoutUserLocally();
            	}
            });
        }
      
        //this function should be called when user logs in and 
        // it will check for messages until user logout
        function checkForMessages(){
            sendAjaxRequest(serviceURL+"/get-next-message/"+sessionID, "GET", {}, possibleActions.CHECK_FOR_MESSAGES);
        }
      
        //here we process all received messages
        function executeReseivedMessage(response){
            var dataObject = jQuery.parseJSON(response);
            
            if(dataObject.msgType == messageTypes.MSG_NO_MESSAGES){
                //nothing to do - do not even log debug message, because log will be fulled
                return;
            }
            
            logProgramMessage("Check for message command executed successfully.Reponse: "+ response, logLevels.DEBUG);
            if (dataObject.msgType == messageTypes.MSG_USER_ONLINE){
                //user came online - we have to show him in users list
                var corespondentMSISDN = dataObject.msisdn;
              
                //clear all existing data for this user
                clearChatInfoWithUser(corespondentMSISDN);
                
                var userExistInList = false;
                //check whether user already exists
                $('.startChat').each(function(){
                    if($(this).html() == corespondentMSISDN){
                        userExistInList=true;
                    }
                });
                if(userExistInList){
                    logProgramMessage("User exist in list, but log again: "+corespondentMSISDN+". Do not add him.", logLevels.INFO);
                    return;
                }
              
                var dataToAppend;
                if($.inArray(corespondentMSISDN, phonebook) > -1){
                    //known number
                    dataToAppend = '<li><a class="startChat">';
                    dataToAppend += corespondentMSISDN;
                    dataToAppend += "</a></li>";
                    //remove no users list item
                    $('#noKnownUsers').remove();
                    $(dataToAppend).insertAfter('#knownUsersDevider');
                    logProgramMessage("Appending user: "+corespondentMSISDN+" to Known numbers list.", logLevels.DEBUG);
                    
                    //remove user from offline list view
                    $('#offline'+corespondentMSISDN.substring(1)).remove();
                    logProgramMessage("Remove user: "+corespondentMSISDN+" from Offline Known numbers list.", logLevels.DEBUG);
                    if($('#offlineUsersDevider').next().length == 0){
                        logProgramMessage("Append \"No offline Known numbers\" node.", logLevels.DEBUG);
                    	var displayProperty = "";
                    	if($('#showOfflineUsers').length){
                    		displayProperty = "display: none;";
                    	}
                        $('<li id="noOfflinePhonebookUsers" class="offlineUsers" style="' + displayProperty + '" data-theme="a">No known users offline</li>').insertAfter('#offlineUsersDevider');
                    }
                } else {
                    //unknown number
                    dataToAppend = '<li data-theme="c"><a class="startChat">';
                    dataToAppend += corespondentMSISDN;
                    dataToAppend += "</a></li>";
                    //remove no users list item
                    $('#noUnknownUsers').remove();
                    $(dataToAppend).insertAfter('#unknownUsersDevider');
                    logProgramMessage("Appending user: "+corespondentMSISDN+" to Unknown numbers list.", logLevels.DEBUG);
                }
                //check whether user sees these changes or we have to notify him
                var homeButtonThem = $('#homeButton').attr("data-theme");
                if(homeButtonThem == "b"){
                    markButtonAsInformationPending("homeButton");
                }
              
                $("#onlineUsersListview").listview('refresh');
                $("#usersPage").page("destroy").page().trigger( 'updatelayout' );
              
            } else if (dataObject.msgType == messageTypes.MSG_USER_OFFLINE){
                //user came offline - we have to stop everything with him
                var corespondentMSISDN = dataObject.msisdn;
              
                //remove user from the list
                $('.startChat').each(function(){
                    if($(this).html() == corespondentMSISDN){
                        $(this).parents('li').remove();
                    }
                });
              
                //clear all chat information
                clearChatInfoWithUser(corespondentMSISDN);
              
                //check whether this was last user
                if($('#knownUsersDevider').next().attr('id') == "unknownUsersDevider"){
                    $('<li id="noKnownUsers">No known users online</li>').insertAfter('#knownUsersDevider');
                } else if($('#unknownUsersDevider').next().attr('id') == "offlineUsersDevider"){
                    $('<li id="noUnknownUsers" data-theme="c">No unknown users online</li>').insertAfter('#unknownUsersDevider');
                }
              
                //check whether user sees these changes or we have to notify him
                var homeButtonThem = $('#homeButton').attr("data-theme");
                if(homeButtonThem == "b"){
                    markButtonAsInformationPending("homeButton");
                }
                
                //check whether to add user to offline users
                if($.inArray(corespondentMSISDN, phonebook) > -1){
                    logProgramMessage("Append user: "+corespondentMSISDN+" to Offline Known numbers list.", logLevels.DEBUG);
                	//remove no offline users node
                	$('#noOfflinePhonebookUsers').remove();
                	//add to list with known offline users
                	var displayProperty = "";
                	if($('#showOfflineUsers').length){
                		displayProperty = "display: none;";
                	}
                	$('<li data-theme="a" id="offline' + corespondentMSISDN.substring(1) + '" style="' + displayProperty + '" class="offlineUsers">' + corespondentMSISDN + "</li>").insertAfter('#offlineUsersDevider');
                }
              
                $("#onlineUsersListview").listview('refresh').trigger('updatelayout');
                
            } else if (dataObject.msgType == messageTypes.MSG_CHALLENGE){
                //we reseave challange, 
                var corespondentMSISDN = dataObject.msisdn;
            
                //we have to show user that someone wants to chat with him
                var challangeKeyReseived = dataObject.msgText;
                logProgramMessage("Received challange key:"+challangeKeyReseived + " from user: " + corespondentMSISDN, logLevels.DEBUG);
                
                //create new buttonForChallengeThisUser
                var button = '<a id="buttonChallange'+corespondentMSISDN.substring(1)+'" class="challangeReceivedButton" data-role="button" data-icon="grid" data-iconpos="left">'
                +corespondentMSISDN+'<input id="challangeKeyReseived'+corespondentMSISDN.substring(1)+'" type="hidden" value="'+challangeKeyReseived+ '"/></a>';
                
                //insert new button
                $(button).insertAfter('#homeButton').trigger( 'updatelayout' );
                markButtonAsInformationPending('buttonChallange'+corespondentMSISDN.substring(1));
                
                //refresh content
                $("#usersPage").page("destroy").page().trigger( 'updatelayout' );
                
            } else if (dataObject.msgType == messageTypes.MSG_RESPONSE){
                //we reseive response from some user
                //check it and start chat
                var corespondentMSISDN = dataObject.msisdn;
                var challangeResponse = dataObject.msgText;
                
                var challangeResponseNumber;
                try{
                    challangeResponseNumber = 999999999 - GibberishAES.dec(challangeResponse, mapUserKey[corespondentMSISDN]);
                } catch (e) {
                    //Key maybe is wronk. We will just send -1 to cancel chat session
                    challangeResponseNumber = -1;
                }
                if(mapUserChallange[corespondentMSISDN] == challangeResponseNumber){
                    //everything is OK
                    logProgramMessage("Everything in response seems OK. Send start chat message to user: "+corespondentMSISDN, logLevels.DEBUG);
                    var data = {
                        "sessionID":sessionID,
                        "recipientMSISDN":corespondentMSISDN
                    };
                  
                    sendAjaxRequest(serviceURL+"/start-chat", "POST", data, possibleActions.START_CHAT, {"corespondentMSISDN":corespondentMSISDN});
                } else {
                    //somthing wrong - deny chat
                    var data = {
                        "sessionID":sessionID,
                        "recipientMSISDN":corespondentMSISDN
                    };
                    sendAjaxRequest(serviceURL+"/cancel-chat", "POST", data, possibleActions.CANCEL_CHAT);
                    showNoConfirmPopup("Fail to establish chat seesion with user: "+ corespondentMSISDN + ".");
                    logProgramMessage("Invalid response key received from user: "+corespondentMSISDN+". Rreject chat.", logLevels.WARN);
                }
                
            } else if (dataObject.msgType == messageTypes.MSG_START_CHAT){
                //Everything seems OK. We will start chat.
                var corespondentMSISDN = dataObject.msisdn;
                startChatWithUser(corespondentMSISDN);
                
            } else if (dataObject.msgType == messageTypes.MSG_CANCEL_CHAT){
                //Something happend during some of chat sessions. Notify user
                var corespondentMSISDN = dataObject.msisdn;
                //clean irrelevant data
                clearChatInfoWithUser(corespondentMSISDN);
                
            } else if (dataObject.msgType == messageTypes.MSG_CHAT_MESSAGE){
                //we receive chat message. Display it
                var corespondentMSISDN = dataObject.msisdn;
                var message;
                try{
                    message = GibberishAES.dec(dataObject.msgText, mapUserKey[corespondentMSISDN]);
                } catch (e) {
                    //Key maybe is wronk. We will just send -1 to cancel chat session
                    message = "error during decrypting";
                }
                logChatMessage(corespondentMSISDN, message, true);
            }
        }
      
        function clearInputData(containerId){
            $('#'+containerId).find(':input').val("");
        }
      
        function listUsersFromServer(){
            sendAjaxRequest(serviceURL+"/list-users/"+sessionID, "GET", {}, possibleActions.LIST);
        }
      
        //Load in home page session with given user
        function startChatWithUser(corespondentMSISDN){
        	logProgramMessage("Start chat session with user: "+corespondentMSISDN, logLevels.INFO);
            //create new buttonForChatWithThisUser
            var button = '<a id="button'+corespondentMSISDN.substring(1)+'" class="activeChatSessionButton" data-role="button" data-icon="grid" data-iconpos="left">'+corespondentMSISDN+'</a>';

            //insert new button
            $(button).insertAfter('#homeButton');
            markButtonAsInformationPending('button'+corespondentMSISDN.substring(1));
          
            //create new one
            var divToDisplay = '<div id="div'+corespondentMSISDN.substring(1)+'" style="display: none" data-theme="d">';
            divToDisplay += '<div style="text-align: center;" class="ui-bar ui-bar-d">';
            divToDisplay += '<a style="float: left;" id="close'+corespondentMSISDN.substring(1)+'" class="closeChatSession ui-btn-left ui-btn-up-a" data-theme="a" data-role="button" data-icon="delete" data-iconpos="left" >Close</a>';
            divToDisplay += '<h3>User '+corespondentMSISDN+'</h3>';
            divToDisplay += '</div>';
            divToDisplay += '<div data-role="content" data-theme="d">';
            divToDisplay += '<div>';
            divToDisplay += '<input class="sendMessageInput" maxlength="31" type="text" id="message'+corespondentMSISDN.substring(1)+'"/>';
            divToDisplay += '<a id="send'+corespondentMSISDN.substring(1)+'" class="sendMessage ui-btn-up-d" data-theme="d" data-role="button" data-icon="arrow-r" data-iconpos="right">Send</a>';
            divToDisplay += '</div>';
            divToDisplay += '</div>';
            divToDisplay += '<div style="padding-left: 1em;" id="history'+corespondentMSISDN.substring(1)+'"></div>';
            divToDisplay += '</div>';
            $(divToDisplay).insertAfter('#onlineUsers');
            //refresh content
            $("#usersPage").page("destroy").page().trigger( 'updatelayout' );

        }
      
        //Load in home page session with given user
        function logChatMessage(corespondentMSISDN, message, isReceived){
            logProgramMessage("Log Chat Message: "+ message +", from user: " + corespondentMSISDN, logLevels.DEBUG);
          
            var dataToAppend = '<p>';
            if(isReceived){
                dataToAppend += '<span style="font-weight:bold; color:red">['+getCurrentTime()+'] You: </span>';
            } else {
                dataToAppend += '<span style="font-weight:bold; color:blue">['+getCurrentTime()+'] Me: </span>';
                // we have to clear data from input field, as we have already send it
                $('#message'+corespondentMSISDN.substring(1)).val("");
            }
            //Escape received message to prevent XSS vulnerabilities
            dataToAppend += htmlEscape(message) +'</p>';
          
            $('#history'+corespondentMSISDN.substring(1)).prepend(dataToAppend).trigger('updatelayout');
          
            //check whether user sees these changes or we have to notify him
            var chatButtonTheme = $('#button'+corespondentMSISDN.substring(1)).attr("data-theme");
            if(chatButtonTheme == "b"){
                markButtonAsInformationPending('button'+corespondentMSISDN.substring(1));
            }
        }
      
        // Read all online users and display them with appropriate meta info 
        function populateListedUsers(arrayWithUsers){
            var divToPosition = $('#onlineUsers');
            divToPosition.empty();
            var dataToAppend = '<ul id="onlineUsersListview" data-role="listview" data-theme="e" data-inset="true">';
            var knownUsers = '';
            var unknownUsers = '';
            $.each(arrayWithUsers,function(index, value){
                if(userMSISDN == value){
                    //do not display self number
                    return;
                }
                if($.inArray(value, phonebook) > -1){
                    //known number
                    knownUsers += '<li><a class="startChat">';
                    knownUsers += value;
                    knownUsers += "</a></li>";
                } else {
                    //unknown number
                    unknownUsers += '<li data-theme="c"><a class="startChat">';
                    unknownUsers += value;
                    unknownUsers += "</a></li>";
                }
            });
            
            //now populate rest users from phonebook as dropdown
            var offlineUsersFromPhonebook = "";
            $.each(phonebook,function(index, value){
                if(userMSISDN == value){
                    //do not display self number
                    return;
                }
                
                if($.inArray(value, arrayWithUsers) == -1){
					//show offline users from phonebook
                    offlineUsersFromPhonebook += '<li data-theme="a" id="offline' + value.substring(1) + '" style="display: none;" class="offlineUsers">';
                    offlineUsersFromPhonebook += value;
                    offlineUsersFromPhonebook += "</li>";
                }
            });
            
            //online known users
            dataToAppend += '<li id="knownUsersDevider" data-role="list-divider"><h4>Known Users</h4></li>';
            if(knownUsers.length > 0){
                dataToAppend += knownUsers;
            } else {
                dataToAppend += '<li id="noKnownUsers">No known users online</li>';
            }
            
            //online unknown users
            dataToAppend += '<li id="unknownUsersDevider" data-role="list-divider"><h4>Unknown Users</h4></li>';
            if(unknownUsers.length > 0){
                dataToAppend += unknownUsers;
            } else {
                dataToAppend += '<li id="noUnknownUsers" data-theme="c">No unknown users online</li>';
            }
            
            //offline known users
            dataToAppend += '<li id="offlineUsersDevider" data-theme="b" data-icon="arrow-r" data-role="list-divider"><a id="showOfflineUsers">Known Offline Users</a></li>';
            if(offlineUsersFromPhonebook.length > 0){
                dataToAppend += offlineUsersFromPhonebook;
            } else {
                dataToAppend += '<li id="noOfflinePhonebookUsers" class="offlineUsers" style="display: none;" data-theme="a">No known users offline</li>';
            }
            
            dataToAppend += '</ul>';
            divToPosition.append(dataToAppend);
            //refresh content
            $("#usersPage").page("destroy").page().trigger( 'updatelayout' );
        }
      
        function startMessageReading(){
            messageLoopID = self.setInterval("checkForMessages()",messageCheckInterval);
        }
      
        function stopMessageReading(){
            messageLoopID = window.clearInterval(messageLoopID);
        }
      
        function markButtonAsSelected(buttonId){
            //first deselect current selected button
            deselectAllButtons();
            
            //add appropriate theme.
            $('#'+buttonId).attr('data-theme','c');
            $('#'+buttonId).removeClass('ui-btn-up-b').removeClass('ui-btn-up-e').removeClass('ui-btn-hover-b').removeClass('ui-btn-hover-e').addClass('ui-btn-up-c');
        }
        
        //deselect all navigation buttons -> from header and footer divs
        function deselectAllButtons(){
        	$('div[data-role="header"] a[data-role="button"]').each(function(){
                if($(this).attr('data-theme') == "c"){
                    $(this).attr('data-theme','b');
                    $(this).removeClass('ui-btn-up-c').removeClass('ui-btn-up-e').removeClass('ui-btn-hover-c').removeClass('ui-btn-hover-e').addClass('ui-btn-up-b');
                }
            });
        	
        	$('div[data-role="footer"] a[data-role="button"]').each(function(){
                if($(this).attr('data-theme') == "c"){
                    $(this).attr('data-theme','b');
                    $(this).removeClass('ui-btn-up-c').removeClass('ui-btn-up-e').removeClass('ui-btn-hover-c').removeClass('ui-btn-hover-e').addClass('ui-btn-up-b');
                }
            });
        }
      
        function markButtonAsInformationPending(buttonId){
            //this should be called when button is not selected e.g it is in theme B.
            $('#'+buttonId).attr('data-theme','e');
            $('#'+buttonId).removeClass('ui-btn-up-b').removeClass('ui-btn-hover-b').addClass('ui-btn-up-e');
        }
      
        function showTabInPage(pageId, tabId){
            //we will hide all derect childs of given page, except header and footer
            $('#' + pageId + ' > div[data-role!="header"]').not('div[data-role="footer"]').each(function(){
                $(this).hide().trigger( 'updatelayout' );
            });
            
            //show tab
            $('#'+tabId).show().trigger( 'updatelayout' );

            //correct focus
            focusFirstVisibleTextField();
        }
      
        //show message to user for few seconds
        function showNoConfirmPopup(message){
            $("<div class='ui-loader ui-overlay-shadow ui-body-e ui-corner-all'><h1><strong>"+message+"</strong></h1></div>")
                .css({ "display":"block", "opacity":0.96, "top": $(window).scrollTop() + 100 })
                .appendTo( $("body") )
                .delay( 2500 )
                .fadeOut( 400, function(){
                    $(this).remove();
                });
        }
      
        function clearChatInfoWithUser(msisdn){
            logProgramMessage("Chat session with user "+ msisdn + " cleared.", logLevels.INFO);
            //check whether we have chat with this user
            if($('#button'+msisdn.substring(1)).length !== 0){
                //notify user
                showNoConfirmPopup("Chat session with "+msisdn+" was closed!");
                //we have to stop this chat
                var chatStatus = $('#button'+msisdn.substring(1)).attr('data-theme');
                if(chatStatus == 'c'){
                    //session is currently active - redirect to online users
                    //unmark all buttons
                    markButtonAsSelected("homeButton");
                    
                    showTabInPage("usersPage", "onlineUsers");
                }
                //close session
                $('#div'+msisdn.substring(1)).remove();
                $('#button'+msisdn.substring(1)).remove().trigger('updatelayout');
            }
        
            //remove additional information
            $('#buttonChallange'+msisdn.substring(1)).remove();
            mapUserChallange[msisdn] = -1;
        }
        
        //check whether user MSISDN is valid
        function invalidUserMSISDN(stringToValidate){
            return stringToValidate == '' || stringToValidate.length <3 || stringToValidate.length >20 
                || stringToValidate.charAt(0) !== "+" || isNaN(stringToValidate.substring(1));
        }
        
        //retrieve current time and return it in format HH:MM:SS
        function getCurrentTime(){
            now = new Date();
            hour = now.getHours();
            min = now.getMinutes();
            sec = now.getSeconds();
            
            if (min <= 9) {
                min = "0" + min;
            }
            if (sec <= 9) {
                sec = "0" + sec;
            }
            if (hour < 10) {
                hour = "0" + hour; 
            }
            
            return hour + ':' + min + ':' + sec;
        }
        
        //log message from program with appropriate log level.
        function logProgramMessage(message, logLevel){
        	if(logLevelEnabled(logLevel)){
        		//change collor of message in case of error
        		var color = "black";
        		if(logLevel == logLevels.WARN){
        			color = "yellow";
        		} else if(logLevel == logLevels.ERROR){
        			color = "red";
        		}
            	var dataToAppend = '<p style="color:' + color + '">';
                dataToAppend += '<span style="font-weight:bold; color:blue">['+getCurrentTime()+'] [' + logLevel + ']: </span>';
                //Escape received message to prevent XSS vulnerabilities
                dataToAppend += htmlEscape(message) +'</p>';
                
                $('#programLogsDiv').prepend(dataToAppend).trigger('updatelayout');
              
                //check whether user sees these changes or we have to notify him
                var chatButtonTheme = $('#programLogsButton').attr("data-theme");
                if(chatButtonTheme == "b"){
                    markButtonAsInformationPending('programLogsButton');
                }
        	}
        }
        
        //check program settings to see which whether given log level have ot be logged
        function logLevelEnabled(logLevel){
        	if(globalLogLevel == logLevels.DEBUG){
        		//log everything in debug level
        		return true;
        	} else if(globalLogLevel == logLevels.INFO && logLevel !== logLevels.DEBUG){
        		return true;
        	} else if(globalLogLevel == logLevels.WARN && logLevel !== logLevels.DEBUG && logLevel !== logLevels.INFO){
        	 	return true;
        	} else if(globalLogLevel == logLevels.ERROR && logLevel == logLevels.ERROR){
        		return true;
        	} else {
        		return false;
        	}
        }
        
        //Redirect user to Login page and clear all irrelevant information.
        function logoutUserLocally(){
        	//stop message readung
        	stopMessageReading();
        	
        	//redirect to login page
        	$.mobile.changePage( "index.html#loginPage", {
                transition: "fade",
                reverse: false,
                changeHash: false
            });
            //clear all irrelevant information
            //clear chat buttons
            $('#usersPage div[data-role="footer"] a[data-role="button"]').each(function(){
                if($(this).attr('id') != "homeButton"){
                    $(this).remove();
                }
            });
            
            //clear content of home page - all divs different from header and footer
            $('#usersPage  > div[data-role!="header"]').not('div[data-role="footer"]').each(function(){
            	if($(this).attr('id') == "programLogsPage"){
            		//save logs locally
            		$(this).find(':first-child').empty();
            		return;
            	}
            	
                if($(this).attr('id') != "onlineUsers"){
                    $(this).remove();
                } else {
                    $(this).empty();
                }
            });
            //clear arrays with chat information
            mapUserKey = {};
            mapUserChallange = {};
        }
        
        //focus on first visible input text field
        function focusFirstVisibleTextField(){
        	$('input[type="text"]:visible').first().focus();
        }
        
      	//focus on first visible input password field
        function focusFirstVisiblePasswordField(){
        	$('input[type="password"]:visible').first().focus();
        }
        